#include "videoplayer.h"
extern "C" {
#include <libavutil/imgutils.h>
}
#include <QtDebug>

int VideoPlayer::initVideoInfo(){
    int ret = initDecoder(&m_vDecodeCtx,&m_vStream,AVMEDIA_TYPE_VIDEO);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "initDecoder error" << errbuf;
        return ret;
    }


    //AVRational time_base = { 1, int(100000 * 2)};
    //m_vStream->time_base = time_base;

    // 初始化像素格式转换
    ret = initSws();
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "initSws error" << errbuf;
        return ret;
    }

    return 0;
}

int VideoPlayer::initSws(){
    int inW = m_vDecodeCtx->width;
    int inH = m_vDecodeCtx->height;

    //输出frame的参数
    m_vSwsOutSpec.width = inW >> 4 << 4;//保证宽度是16的倍数
    m_vSwsOutSpec.height = inH >> 4 << 4;
    m_vSwsOutSpec.pixFmt = AV_PIX_FMT_RGB24;
    //m_vSwsOutSpec.pixFmt = AV_PIX_FMT_YUV420P;
    m_vSwsOutSpec.size = av_image_get_buffer_size(m_vSwsOutSpec.pixFmt,m_vSwsOutSpec.width,m_vSwsOutSpec.height,1);

    //初始化像素格式转换的上下文
    m_vSwsCtx = sws_getContext(inW,inH,m_vDecodeCtx->pix_fmt,m_vSwsOutSpec.width,
                               m_vSwsOutSpec.height,m_vSwsOutSpec.pixFmt,SWS_BILINEAR,nullptr,nullptr,nullptr);
    //SWS_BILINEAR 双线性插值算法
    if (!m_vSwsCtx) {
        qDebug() << "sws_getContext error";
        return -1;
    }

    //初始化像素格式转换的输入frame
    m_vSwsInFrame = av_frame_alloc();
    if(!m_vSwsInFrame){
        qDebug() << "av_frame_alloc error";
        return -1;
    }

    //初始化像素格式转换的输出frame
    m_vSwsOutFrame = av_frame_alloc();
    if(!m_vSwsOutFrame){
        qDebug() << "av_frame_alloc error";
        return -1;
    }

    // _vSwsOutFrame的data[0]指向的内存空间
    int ret = av_image_alloc(m_vSwsOutFrame->data,
                             m_vSwsOutFrame->linesize,
                             m_vSwsOutSpec.width,
                             m_vSwsOutSpec.height,
                             m_vSwsOutSpec.pixFmt,
                             1);
    if(ret < 0){
        char errbuf[1024];
        av_strerror(ret,errbuf,sizeof(errbuf));
        qDebug() << "av_image_alloc error" << errbuf;
        return ret;
    }
    return 0;
}


int VideoPlayer::decodeVideo(){
    while(true){
        //TODO 这个地方逻辑有点问题，似乎有点消耗CPU
        //如果是暂停,并且没有seek操作
        if(m_TaskState == Paused && m_vSeekTime == -1){
            continue;
        }

        if(m_TaskState == Stopped){
            m_vCanFree = true;
            break;
        }

        m_vMutex.lock();
        if(m_vPktList.empty()){
            m_vMutex.unlock();
            continue;
        }

        //取出头部的视频包
        AVPacket pkt = m_vPktList.front();
        m_vPktList.pop_front();
        m_vMutex.unlock();

        //视频时钟
        if(pkt.dts != AV_NOPTS_VALUE){
            m_vTime = av_q2d(m_vStream->time_base) * pkt.dts;
        }

        //发送压缩数据到解码器
        if(pkt.dts < 0){
            pkt.dts = 0;
        }
        int ret = avcodec_send_packet(m_vDecodeCtx,&pkt);
        //释放pkt
        av_packet_unref(&pkt);
        if(ret < 0){
            char errbuf[1024];
            av_strerror(ret,errbuf,sizeof(errbuf));
            qDebug() << "av_packet_unref error" << errbuf;
            continue;
        }

        while(true){
            ret = avcodec_receive_frame(m_vDecodeCtx,m_vSwsInFrame);
            if(ret == AVERROR(EAGAIN) || ret == AVERROR(EOF)){
                break;
            }else{
                if(ret < 0){
                    char errbuf[1024];
                    av_strerror(ret,errbuf,sizeof(errbuf));
                    qDebug() << "av_packet_unref error" << errbuf;
                    break;
                }
            }

            //一定要在解码成功后，再进行下面的判断
            //发现视频的时间早于seekTime，直接丢弃
            if(m_vSeekTime >= 0){
                if(m_vTime < m_vSeekTime){
                    continue;
                }else{
                    m_vSeekTime = -1;
                }
            }

            //像素格式的转换
            //TODO 可用多线程
            sws_scale(m_vSwsCtx,m_vSwsInFrame->data,m_vSwsInFrame->linesize,0,m_vDecodeCtx->height,m_vSwsOutFrame->data,m_vSwsOutFrame->linesize);
            if(m_bHasAudio){// 有音频
                // 如果视频包过早被解码出来，那就需要等待对应的音频时钟到达
                while (m_vTime > m_aTime && m_TaskState == Playing) {
                    SDL_Delay(1);
                }
            }

            uint8_t *data = (uint8_t *)av_malloc(m_vSwsOutSpec.size);
            memcpy(data, m_vSwsOutFrame->data[0], m_vSwsOutSpec.size);
            // 发出信号
            emit frameDecoded(this,data,m_vSwsOutSpec);
            //TODO
            //qDebug()<< "渲染了一帧"<< m_vTime << m_aTime;
        }
    }
    return 0;
}


void VideoPlayer::addVideoPkt(AVPacket &pkt){
    m_vMutex.lock();
    m_vPktList.push_back(pkt);
    m_vMutex.signal();
    m_vMutex.unlock();
}
